package com.iflytek.iot.common.utils;

import java.sql.Timestamp;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 时间转换工具
 *
 * @author yu 2018/11/30.
 */
public class DateUtils {

    private static final ConcurrentMap<String, DateTimeFormatter> FORMATTER_CACHE = new ConcurrentHashMap<>();

    private static final int PATTERN_CACHE_SIZE = 500;

    public static final String HHMMSS = "HHmmss";

    public static final String HH_MM_SS = "HH:mm:ss";

    public static final String YYYYMMDD = "yyyyMMdd";

    public static final String YYYY_MM_DD = "yyyy-MM-dd";

    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static final String YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";

    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    public static final String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";

    /**
     * 中国时间年月日
     */
    public static final String DATE_FORMAT_CHINESE = "yyyy年MM月dd日";

    /**
     * 中国时间格式包含年月日时分秒
     */
    public static final String DATE_FORMAT_CHINESE_SECONDE = "yyyy年MM月dd日 HH:mm:ss";

    /**
     * 一天的毫秒数
     */
    public static final long DAY_MS = 86400000L;

    /**
     * 12小时格式
     */
    public static final String DATE_MINUTES_12 = "yyyy-MM-dd hh-mm-ss";


    /**
     * 获取当前时间戳
     *
     * @return java.sql.Timestamp
     */
    public static Timestamp nowTimeStamp() {
        return new Timestamp(System.currentTimeMillis());
    }

    /**
     * 字符串时间戳
     *
     * @return
     */
    public static String nowStrTime() {
        return long2Str(System.currentTimeMillis(), YYYY_MM_DD_HH_MM_SS);
    }


    /**
     * 字符串时间
     *
     * @param pattern 模式
     * @return String
     */
    public static String nowStrTime(String pattern) {
        return long2Str(System.currentTimeMillis(), pattern);
    }

    /**
     * 获取当前的字符串日期
     *
     * @return
     */
    public static String nowStrDate() {
        return LocalDate.now().toString();
    }

    /**
     * 返回12小时制的时间
     *
     * @return
     */
    public static String nowStrTime12() {
        return long2Str(System.currentTimeMillis(), DATE_MINUTES_12);
    }

    /**
     * 将毫秒时间格式化为指定格式的字符串时间
     *
     * @param millSec 毫秒
     * @param pattern 需要格式的样式(yyyy-MM-dd等)
     * @return String
     */
    public static String long2Str(long millSec, String pattern) {
        Date date = new Date(millSec);
        return dateToStr(date, pattern);
    }

    /**
     * transfer string to long,兼容日期类型和时间戳
     *
     * @param strTime String
     * @param pattern String
     * @return long
     */
    public static long strToLong(String strTime, String pattern) {
        try{
            return LocalDateTimeToLong(parseLocalDateTime(strTime, pattern));
        }catch (Exception e){

        }
        return localDateToLong(parseLocalDate(strTime, pattern));
    }

    /**
     * Formats a java.util.Date using a format string
     *
     * @param date    The date to format
     * @param pattern The pattern string like yyyy-MM-dd
     * @return String
     */
    public static String dateToStr(Date date, String pattern) {
        return format(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()), pattern);
    }

    /**
     * Parses a date using a specified format string
     *
     * @param sDate   String
     * @param pattern String
     * @return Date
     */
    public static Date strToDate(String sDate, String pattern) {
        LocalDate localDate = parseLocalDate(sDate, pattern);
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
        return Date.from(zdt.toInstant());
    }

    /**
     * Convert String to Timestamp
     *
     * @param date    String of date content
     * @param pattern data pattern
     * @return Timestamp
     */
    public static Timestamp strToTimestamp(String date, String pattern) {
        LocalDateTime localDateTime = parseLocalDateTime(date, pattern);
        return Timestamp.valueOf(localDateTime);
    }

    /**
     * format TimeStamp to string
     *
     * @param time java.sql.Timestamp
     * @param fmt  String
     * @return String
     */
    public static String timestampToStr(Timestamp time, String fmt) {
        DateTimeFormatter dateTimeFormatter = createCacheFormatter(fmt);
        LocalDateTime dateTime = time.toLocalDateTime();
        return dateTimeFormatter.format(dateTime);
    }

    /**
     * calc age
     *
     * @param strDate birthday
     * @return int
     */
    public static int getAge(String strDate) {
        LocalDate now = LocalDate.now();
        LocalDate born = parseLocalDate(strDate, YYYY_MM_DD);
        int age;
        if (born.isAfter(now)) {
            return -1;
        }
        age = now.getYear() - born.getYear();
        if (now.getYear() < born.getYear()) {
            age -= 1;
        }
        return age;
    }

    /**
     * calc age,if born in the future return -1
     *
     * @param ms long
     * @return int
     */
    public static int getAge(long ms) {
        int age;
        Calendar born = Calendar.getInstance();
        Calendar now = Calendar.getInstance();
        born.setTimeInMillis(ms);
        if (born.after(now)) {
            return -1;
        }
        age = now.get(Calendar.YEAR) - born.get(Calendar.YEAR);
        if (now.get(Calendar.DAY_OF_YEAR) < born.get(Calendar.DAY_OF_YEAR)) {
            age -= 1;
        }
        return age;
    }

    /**
     * 判断是否是同一天
     *
     * @param calendar1 Calendar
     * @param calendar2 Calendar
     * @return boolean
     */
    public static boolean isDifferentDay(Calendar calendar1, Calendar calendar2) {
        return (calendar1.get(Calendar.YEAR) != calendar2.get(Calendar.YEAR) || calendar1
                .get(Calendar.DAY_OF_YEAR) != calendar2
                .get(Calendar.DAY_OF_YEAR));
    }

    /**
     * 判断是否是同一天
     *
     * @param timestamp0 java.sql.Timestamp
     * @param timestamp1 java.sql.Timestamp
     * @return boolean
     */
    public static boolean isDifferentDay(Timestamp timestamp0, Timestamp timestamp1) {
        if (timestamp0 == null || timestamp1 == null) {
            throw new NullPointerException("Timestamp can not be null");
        } else {
            Calendar cal1 = Calendar.getInstance();
            cal1.setTimeInMillis(timestamp0.getTime());
            Calendar cal2 = Calendar.getInstance();
            cal2.setTimeInMillis(timestamp1.getTime());
            return isDifferentDay(cal1, cal2);
        }
    }

    /**
     * 判断是否是同一天
     *
     * @param millis0 long
     * @param millis1 long
     * @return boolean
     */
    public static boolean isDifferentDay(long millis0, long millis1) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTimeInMillis(millis0);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTimeInMillis(millis1);
        return isDifferentDay(cal1, cal2);
    }


    /**
     * 验证字符串时间格式是否符合要求
     *
     * @param timeStr 字符串时间
     * @param pattern 匹配格式
     * @return
     */
    public static boolean checkStrTime(String timeStr, String pattern) {
        DateTimeFormatter formatter = createCacheFormatter(pattern);
        try {
            return (LocalDate.parse(timeStr, formatter) != null) || (LocalDateTime.parse(pattern, formatter) != null);
        } catch (Exception e) {
            return Boolean.FALSE;
        }
    }

    /**
     * localDateTime转换为格式化时间
     *
     * @param localDateTime localDateTime
     * @param pattern       格式
     * @return
     */
    public static String format(LocalDateTime localDateTime, String pattern) {
        DateTimeFormatter formatter = createCacheFormatter(pattern);
        return localDateTime.format(formatter);
    }

    /**
     * 格式化字符串转为LocalDateTime
     *
     * @param time    格式化时间
     * @param pattern 格式
     * @return
     */
    public static LocalDateTime parseLocalDateTime(String time, String pattern) {
        DateTimeFormatter formatter = createCacheFormatter(pattern);
        return LocalDateTime.parse(time, formatter);
    }

    /**
     * LocalDateTime 转化成long
     *
     * @param dateTime LocalDateTime
     * @return
     */
    public static long LocalDateTimeToLong(LocalDateTime dateTime) {
        Long milliSecond = dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        return milliSecond;
    }

    /**
     * 字符串转化成LocalDate
     *
     * @param time    格式化时间
     * @param pattern 格式
     * @return
     */
    public static LocalDate parseLocalDate(String time, String pattern) {
        DateTimeFormatter formatter = createCacheFormatter(pattern);
        return LocalDate.parse(time, formatter);
    }

    /**
     * localDate转时间戳
     * @param localDate
     * @return long
     */
    public static long localDateToLong(LocalDate localDate){
        return localDate.atStartOfDay(ZoneId.systemDefault()).toEpochSecond()*1000;
    }

    /**
     * 在缓存中创建DateTimeFormatter
     *
     * @param pattern 格式
     * @return
     */
    private static DateTimeFormatter createCacheFormatter(String pattern) {
        if (pattern == null || pattern.length() == 0) {
            throw new IllegalArgumentException("Invalid pattern specification");
        }
        DateTimeFormatter formatter = FORMATTER_CACHE.get(pattern);
        if (formatter == null) {
            if (FORMATTER_CACHE.size() < PATTERN_CACHE_SIZE) {
                formatter = DateTimeFormatter.ofPattern(pattern);
                DateTimeFormatter oldFormatter = FORMATTER_CACHE.putIfAbsent(pattern, formatter);
                if (oldFormatter != null) {
                    formatter = oldFormatter;
                }
            }
        }
        return formatter;
    }


}
